package com.gomoku;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler.Callback;
import android.os.Message;
import android.util.Size;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.common.GameBoard;
import com.common.InputBox;

// 主窗口
public class MainActivity extends Activity implements Callback, GameBoard.Callback, InputBox.Callback, MenuItem.OnMenuItemClickListener, View.OnTouchListener {
    private Game mGame;                     // 游戏
    private TextView mLabelRivalName;       // "当前对手"标签
    private MenuItem mMenuItemDefeat;       // "认输"菜单项
    private MenuItem mMenuItemFindUsers;    // "寻找其它用户"菜单项
    private MenuItem mMenuItemRestart;      // "再来一局"菜单项
    private RivalWindow mRivalWindow;       // 对手列表窗口

    /**
     * 自定义事件的响应方法。
     * @param message   事件相关信息
     * @return 事件在此被处理则返回 true，否则返回 false
     */
    @Override
    public boolean handleMessage(Message message) {
        switch (message.what) {
            case Const.UM_CONNECTED:
                this.onConnected((Boolean)message.obj);
                return true;
            case Const.UM_GET_FIND_USERS_RESULT:
                this.onGetFindUsersResult((FindUsersResult)message.obj);
                return true;
            case Const.UM_GAME_OVER:
                this.onGameOver(GameOverReason.values()[message.arg1]);
                return true;
            case Const.UM_GAME_START:
                this.onGameStart((String)message.obj);
                return true;
            case Const.UM_GET_INVITE_REQUEST:
                this.onGetInviteRequest((String)message.obj);
                return true;
            case Const.UM_GET_INVITE_RESULT:
                this.onGetInviteResult((String)message.obj, message.arg1 == 1);
                return true;
            case Const.UM_GET_LOGON_RESULT:
                this.onGetLogonResult((boolean)message.obj);
                return true;
            case Const.UM_GET_RIVAL_NAME:
                this.onGetRivalName((String)message.obj);
                return true;
            case Const.UM_RIVAL_QUIT_GAME:
                this.onRivalQuitGame(message.arg1 == 1, (String)message.obj);
                return true;
        }
        return false;
    }

    /**
     * 网络连接完成事件的响应方法。
     * @param result    成功则为 true，否则为 false
     */
    private void onConnected(boolean result) {
        if (result) {
            // 登录
            new InputBox(this, this, R.string.IDS_INPUT_USERNAME).show();
        } else {
            // 弹出提示
            new AlertDialog.Builder(this)
                .setCancelable(false)
                .setMessage(R.string.IDS_NETWORK_ERROR)
                .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> System.exit(0))
                .show();
        }
    }

    /**
     * 创建事件的响应方法。
     * @param savedInstanceState   保存的实例状态
     */
    @SuppressLint("MissingSuperCall")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.setContentView(R.layout.activity_main);

        // 创建对手列表窗口
        mRivalWindow = new RivalWindow(this, this);

        // 设置游戏区域回调
        final GameBoard gameBoard = super.findViewById(R.id.IDC_GAME_BOARD);
        gameBoard.setCallback(this);
    }

    /**
     * 创建菜单事件的响应方法。
     * @param menu  菜单
     * @return 总是 true
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.getMenuInflater().inflate(R.menu.main, menu);

        // 创建菜单项
        mMenuItemDefeat = menu.findItem(R.id.IDC_DEFEAT);
        mMenuItemFindUsers = menu.findItem(R.id.IDC_FIND_RIVAL);
        mMenuItemRestart = menu.findItem(R.id.IDC_RESTART);

        // 菜单项添加事件监听者
        mMenuItemDefeat.setOnMenuItemClickListener(this);
        mMenuItemFindUsers.setOnMenuItemClickListener(this);
        mMenuItemRestart.setOnMenuItemClickListener(this);

        return true;
    }

    /**
     * 销毁事件的响应方法。
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        mGame.close();
    }

    /**
     * 游戏区域度量尺寸事件的响应方法。
     * @param gameBoard         游戏区域
     * @param widthMeasureSpec  父控件指定的宽度值
     * @param heightMeasureSpec 父控件指定的高度值
     * @return 游戏区域的尺寸
     */
    @Override
    public Size onGameBoardMeasure(View gameBoard, int widthMeasureSpec, int heightMeasureSpec) {
        // 获取可用的最大屏幕尺寸
        final int screenMaxWidth = View.MeasureSpec.getSize(widthMeasureSpec);

        // 计算格的尺寸
        final int gridCount = Const.GAME_BOARD_POINT_COUNT_H + 1;
        Const.GRID_SIZE = screenMaxWidth / gridCount;

        // 创建后台缓冲位图和绘图者
        final int width = Const.GRID_SIZE * gridCount;
        final int height = Const.GRID_SIZE * gridCount;

        return new Size(width, height);
    }

    /**
     * 游戏结束事件的响应方法。
     * @param reason    结束原因
     */
    private void onGameOver(GameOverReason reason) {
        // 设置菜单项
        mMenuItemFindUsers.setEnabled(true);
        mMenuItemDefeat.setEnabled(false);
        mMenuItemRestart.setEnabled(true);

        // 显示提示信息
        int stringId = 0;
        switch (reason) {
            case LOST:
                stringId = R.string.IDS_LOST;
                break;
            case RIVAL_ADMIT:
                stringId = R.string.IDS_RIVAL_ADMIT;
                break;
            case SELF_ADMIT:
                stringId = R.string.IDS_SELF_ADMIT;
                break;
            case WON:
                stringId = R.string.IDS_WON;
                break;
        }
        new AlertDialog.Builder(this)
            .setCancelable(false)
            .setMessage(stringId)
            .setPositiveButton(android.R.string.ok, null)
            .show();
    }

    /**
     * 游戏开始事件的响应方法。
     * @param rivalName 对手的名字
     */
    private void onGameStart(String rivalName) {
        // 隐藏对手列表窗口
        if (mRivalWindow != null) {
            mRivalWindow.hide();
        }

        // 设置菜单项
        mMenuItemFindUsers.setEnabled(false);
        mMenuItemDefeat.setEnabled(true);
        mMenuItemRestart.setEnabled(false);

        // 显示对手的名字
        final String text = super.getString(R.string.IDS_CURRENT_RIVAL) + rivalName;
        mLabelRivalName.setText(text);
    }

    /**
     * 得到寻找用户结果事件的响应方法。
     * @param result    结果
     */
    private void onGetFindUsersResult(FindUsersResult result) {
        if (result.mUsernameList != null) {
            String[] usernameList = new String[result.mUsernameList.size()];
            usernameList = result.mUsernameList.toArray(usernameList);
            mRivalWindow.setUsernameList(usernameList);
            mRivalWindow.show();
        }
    }

    /**
     * 得到挑战请求事件的响应方法。
     * @param rivalName 对手的名字
     */
    private void onGetInviteRequest(final String rivalName) {
        final String question = rivalName + super.getString(R.string.IDS_INVITE);
        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
            /**
             * 所有按钮的单击响应方法。
             * @param dialog        对话框
             * @param clickedButton 按钮索引
             */
            @Override
            public void onClick(DialogInterface dialog, int clickedButton) {
                // 发送结果
                final boolean accept = clickedButton == AlertDialog.BUTTON_POSITIVE;
                mGame.acceptInvite(rivalName, accept);
            }
        };
        new AlertDialog.Builder(this)
            .setCancelable(false)
            .setMessage(question)
            .setPositiveButton(android.R.string.yes, listener)
            .setNegativeButton(android.R.string.no, listener)
            .show();
    }

    /**
     * 得到挑战结果事件的响应方法。
     * @param rivalName 对手的名字
     * @param accept    接受挑战则为 true，否则为 false
     */
    private void onGetInviteResult(String rivalName, boolean accept) {
        String information = rivalName;
        if (accept) {
            information += super.getString(R.string.IDS_ACCEPT);
        } else {
            information += super.getString(R.string.IDS_REFUSE);
        }

        new AlertDialog.Builder(this)
            .setCancelable(false)
            .setMessage(information)
            .setPositiveButton(android.R.string.ok, null)
            .show();
    }

    /**
     * 得到登录结果事件的响应方法。
     * @param succeeded 登录结果
     */
    private void onGetLogonResult(boolean succeeded) {
        if (succeeded) {
            Toast.makeText(this, R.string.IDS_LOGON_SUCCEEDED, Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, R.string.IDS_LOGON_FAILED, Toast.LENGTH_SHORT).show();
            new InputBox(this, this, R.string.IDS_INPUT_USERNAME).show();
        }
    }

    /**
     * 获取对手的名字事件的响应方法。
     * @param rivalName 对手的名字
     */
    private void onGetRivalName(String rivalName) {
        mGame.invite(rivalName);
    }

    /**
     * 输入窗口的"取消"按钮的单击响应方法。
     */
    @Override
    public void onInputBoxCancel() {
        mGame.close();
        System.exit(0);
    }

    /**
     * 输入窗口的"确定"按钮的单击响应方法。
     * @param intValue  用户输入的数值
     */
    @Override
    public void onInputBoxOK(int intValue) {
    }

    /**
     * 输入窗口的"确定"按钮的单击响应方法。
     * @param stringValue   用户输入的文字
     */
    @Override
    public void onInputBoxOK(String stringValue) {
        mGame.logon(stringValue);
    }

    /**
     * 所有菜单项的单击响应方法。
     * @param item  用户单击的菜单项
     * @return 事件在此被处理则返回 true，否则返回 false
     */
    @SuppressLint("NonConstantResourceId")
    @Override
    public boolean onMenuItemClick(MenuItem item) {
        final int id = item.getItemId();
        if (id == R.id.IDC_DEFEAT) {
            this.onMenuItemDefeatClicked();
            return true;
        }
        if (id == R.id.IDC_FIND_RIVAL) {
            this.onMenuItemFindUsersClicked();
            return true;
        }
        if (id == R.id.IDC_RESTART) {
            this.onMenuItemRestartClicked();
            return true;
        }

        return false;
    }

    /**
     * "认输"菜单项的单击响应方法。
     */
    private void onMenuItemDefeatClicked() {
        mGame.defeat();
    }

    /**
     * "寻找其它用户"菜单项的单击响应方法。
     */
    private void onMenuItemFindUsersClicked() {
        mGame.findUsers();
    }

    /**
     * "再来一局"菜单项的单击响应方法。
     */
    private void onMenuItemRestartClicked() {
        mGame.restart();
    }

    /**
     * 对手退出游戏事件的响应方法。
     * @param escape    对手逃跑则为 true，正常退出则为 false
     * @param rivalName 对手的名字
     */
    private void onRivalQuitGame(boolean escape, String rivalName) {
        // 设置菜单项
        mMenuItemFindUsers.setEnabled(true);
        mMenuItemDefeat.setEnabled(false);
        mMenuItemRestart.setEnabled(false);

        // 设置状态栏
        mLabelRivalName.setText(R.string.IDS_CURRENT_RIVAL);

        // 显示提示信息
        String text = rivalName;
        if (escape) {
            text += super.getString(R.string.IDS_RIVAL_ESCAPE);
            new AlertDialog.Builder(this)
                .setCancelable(false)
                .setMessage(text)
                .setPositiveButton(android.R.string.ok, null)
                .show();
        } else {
            text += super.getString(R.string.IDS_RIVAL_QUIT);
            Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 单击游戏区域事件的响应方法。
     * @param view  被单击的视图
     * @param e     事件相关信息
     * @return 事件在此被处理则返回 true，否则返回 false
     */
    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouch(View view, MotionEvent e) {
        if (e.getAction() == MotionEvent.ACTION_DOWN) {
            mGame.onGameBoardClicked((int)e.getX(), (int)e.getY());
            return true;
        }
        return false;
    }

    /**
     * 焦点变化事件的响应方法。
     * @param hasFocus  获得了焦点则为 true，否则为 false
     */
    @SuppressLint("ClickableViewAccessibility")
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (mGame == null) {
            mLabelRivalName = super.findViewById(R.id.IDC_LABEL_RIVAL_NAME);

            // 创建游戏区域
            final GameBoard gameBoard = super.findViewById(R.id.IDC_GAME_BOARD);
            gameBoard.setOnTouchListener(this);

            // 创建游戏
            mGame = new Game(this, gameBoard.getDrawer(), gameBoard);
        }
    }
}
